#include <string.h>

#include "../Defines.h"
#include "TouchInput.h"
//#include "../Log.h"
#include "Point.h"
#include "game.h"

const float regionTolerance = 0.1f;


Region& Region::operator =(Region &s)
{
	int l = strlen(s.name);
	strcpy(name, s.name);
	name[l] = 0;

	shape = s.shape;
	x = s.x;
	y = s.y;
	w = s.w;
	h = s.h;
	r = s.r;

	return *this;
}

Region::Region()
{
	shape = SHAPE_UNKNOWN;
	x = -1;
	y = -1;
	w = -1;
	h = -1;
	r = -1;
}

Region::Region(const char* n, regionShape s, float sx, float sy, float sw, float sh, float sr)
{
	int l = strlen(n);
	strcpy(name, n);
	name[l] = 0;

	shape = s;
	x = sx;
	y = sy;
	w = sw;
	h = sh;
	r = sr;
}

void CTouchInput::InitMouseState()
{
	isMousePressed = false;
	isMouseDragging = false;
	isRegionPressed = false;
	isMouseDown		= false;
	isRegionsEnabled	= true;

	posX = -1;
	posY = -1;
	oldPosX = -1;
	oldPosY = -1;
	time = -1;
	lastTime = -1;
	moveSpeedX = 0;
	moveSpeedY = 0;

	startDragX = -1;
	startDragY = -1;
	endDragX = -1;
	endDragY = -1;
	downRegion = -1;
	oldDownRegion = -1;

	dragInTap = 0;
}

CTouchInput::CTouchInput()
{
	InitMouseState();

	for (int i = 0; i < MAX_REGIONS; i++)
		activeRegions[i].shape = SHAPE_UNKNOWN;
	regionNum = 0;

}

void CTouchInput::EnableDisableRegions(bool flag)
{
	isRegionsEnabled = flag;
}

bool CTouchInput::IsRegionsEnabled()
{
	return isRegionsEnabled;
}

void CTouchInput::SetMousePressed()
{
	isMousePressed = true;
}

void CTouchInput::SetMouseDragging()
{
	isMouseDragging = true;
	isMousePressed = false;
}

void CTouchInput::SetMouseFree()
{
	InitMouseState();
}

void CTouchInput::SetMousePos(int x, int y)
{
	if (x >= 0 && x <= SCREEN_WIDTH)
	{
		posX = x;
	}
	if (y >= 0 && y <= SCREEN_HEIGHT)
	{
		posY = y;
	}
}

void CTouchInput::SetMouseTime()
{
	time = S_GetTime();
}

int CTouchInput::GetMousePosX()
{
	return posX;
}

int CTouchInput::GetMousePosY()
{
	return posY;
}

Point2D CTouchInput::GetMousePosition()
{
	Point2D p(posX, posY);
	return p;
}

int CTouchInput::GetMouseOldPosX()
{
	return oldPosX;
}

int CTouchInput::GetMouseOldPosY()
{
	return oldPosY;
}

int CTouchInput::GetMouseMoveSpeedX()
{
	return moveSpeedX;
}

int CTouchInput::GetMouseMoveSpeedY()
{
	return moveSpeedY;
}

int	CTouchInput::GetStartDragX()
{
	return startDragX;
}

int	CTouchInput::GetStartDragY()
{
	return startDragY;
}

int	CTouchInput::GetEndDragX()
{
	return endDragX;
}

int	CTouchInput::GetEndDragY()
{
	return endDragY;
}

bool CTouchInput::IsMousePressed()
{
	return isMousePressed;
}

bool CTouchInput::IsMouseDragging()
{
	return isMouseDragging;
}

bool CTouchInput::AddRegion(Region r)
{
	if (regionNum < MAX_REGIONS)
	{
		if (r.shape != SHAPE_UNKNOWN)
		{
			activeRegions[regionNum] = r;
			regionNum++;
			return true;
		}
	}

	S_Print("Add Region Error\n");
	return false;
}

bool CTouchInput::RemoveRegion(const char* name)
{
	int index;
	for (index = 0; index < regionNum; index++)
	{
		if (strcmp(activeRegions[index].name, name) == 0)
			break;
	}

	if (index >= regionNum)
		return false;

	for (int i = index; i < regionNum - 1; i++)
	{
		activeRegions[i] = activeRegions[i + 1];
	}
	regionNum--;
	return true;
}

bool CTouchInput::ExistsRegion(const char *region)
{
	int index;
	for (index = 0; index < regionNum; index++)
	{
		if (strcmp(activeRegions[index].name, region) == 0)
		{
			return true;
		}
	}
	return false;
}

void CTouchInput::ClearRegion()
{
	for (int i = 0; i < regionNum; i++)
	{
		activeRegions[i].shape = SHAPE_UNKNOWN;
	}
	regionNum = 0;
	downRegion = -1;
}

int CTouchInput::IndexOfRegion(const char* name)
{
	int index;
	for (index  = 0; index < regionNum; index++)
	{
		if (strcmp(activeRegions[index].name, name) == 0)
			return index;
	}

	return -1;
}

bool CTouchInput::IsMouseInRegion(const char* name)
{
	if (!isRegionsEnabled)
	{
		return false;
	}

	int index;
	for (index  = 0; index < regionNum; index++)
	{
		if (strcmp(activeRegions[index].name, name) == 0)
			break;
	}

	if (index >= regionNum)
	{
		S_Print("Is Mouse In Region: Not found\n");
		return false;
	}

	float var = 0;

	if(isMouseDown && (downRegion == index || oldDownRegion == index))
	{
		var = regionTolerance;
	}

	b2Vec2 fPos = ConvertScreenToWorld(posX,posY);
	switch (activeRegions[index].shape)
	{
	case SHAPE_RECT:
		if ((fPos.x >= activeRegions[index].x - var && fPos.x <= activeRegions[index].x + activeRegions[index].w + var) &&
			(fPos.y >= activeRegions[index].y - var && fPos.y <= activeRegions[index].y + activeRegions[index].h + var))
			return true;
		else
			return false;
	case SHAPE_CIRCLE:
		if ((fPos.x - activeRegions[index].x) * (fPos.x - activeRegions[index].x) + (fPos.y - activeRegions[index].y) * (fPos.y - activeRegions[index].y)
			<= activeRegions[index].r * activeRegions[index].r + var)
			return true;
		else
			return false;
	default:
		S_Print("Is Mouse In Region: Shape unknown!\n");
		return false;
	}
}

#define SPEED_FACTOR 10000

// Variables for iphone event process
mouseState state;
int	originalPosX;
int	originalPosY;

void CTouchInput::Update()
{
	if(isMouseUp)
	{
		mouseDownSkiped = false;
		isMouseUp = false;
		downRegion = -1;
		oldDownRegion = -1;
	}
	switch (state)
	{
	case STATE_UNKNOWN:
		SetMouseFree();
		break;
	case STATE_DOWN:
		isMouseDown = true;
		SetMousePos(originalPosX, originalPosY);
		SetMouseTime();
		startDragX = originalPosX;
		startDragY = originalPosY;
		downRegion = GetSelectedRegion();
		dragInTap = DRAG_IN_TAP;
		break;
	case STATE_DRAGGED:
		{
		bool setMouseDown = false;
		if (dragInTap <= 0 && !isMouseDragging)
		{
			SetMouseDragging();
			if(!isMouseDown)
			{
				SetMousePos(originalPosX, originalPosY);
				SetMouseTime();
				startDragX = originalPosX;
				startDragY = originalPosY;
				downRegion = GetSelectedRegion();
				setMouseDown = true;
			}
		}

		if (dragInTap > 0)
		{
			dragInTap--;
		}
		oldPosX = posX;
		oldPosY = posY;
		lastTime = time;
		SetMousePos(originalPosX, originalPosY);
		SetMouseTime();
		moveSpeedX = (posX - oldPosX) * SPEED_FACTOR / (time - lastTime > 0 ? time - lastTime : 1);
		moveSpeedY = (posY - oldPosY) * SPEED_FACTOR / (time - lastTime > 0 ? time - lastTime : 1);

		downRegion = GetSelectedRegion();

		if(downRegion >= 0 && !IsMouseInRegion(activeRegions[downRegion].name))
		{
			oldDownRegion = downRegion;
			downRegion = -1;
		}
		else if(oldDownRegion >= 0 && IsMouseInRegion(activeRegions[oldDownRegion].name))
		{
			downRegion = oldDownRegion;
			oldDownRegion = -1;
		}

		isMouseDown = setMouseDown;
		}
		break;
	case STATE_UP:
		isMouseUp = true;
		if (isMouseDragging)
		{
			endDragX = originalPosX;
			endDragY = originalPosY;
		}
		else
		{
			SetMousePressed();
			SetMousePos(originalPosX, originalPosY);
		}

/*
		if(!isMouseDown)
		{
			mouseDownSkiped = true;
			downRegion == GetSelectedRegion();
		}
*/
		if (downRegion == GetSelectedRegion() && downRegion != -1)
		{
			isRegionPressed = true;
		}

		isMouseDown = false;
		state = STATE_UNKNOWN;
		break;
	}
}

bool CTouchInput::IsMouseDown()
{
	return state == STATE_DOWN || isMouseDown;
}

bool CTouchInput::IsMouseDownSkipped()
{
	return mouseDownSkiped;
}

bool CTouchInput::IsMouseUp()
{
	return isMouseUp;
}

bool CTouchInput::IsRegionPressed(const char *name)
{
	if (!isRegionsEnabled)
	{
		return false;
	}

	return isRegionPressed && (downRegion == IndexOfRegion(name));
}

bool CTouchInput::IsRegionPressedMult(const char *name)
{
	if (!isRegionsEnabled)
	{
		return false;
	}

	return isRegionPressed && IsMouseInRegion(name);
}

void CTouchInput::Clear()
{
	isRegionPressed = false;
	isMouseUp = false;
	isMousePressed = false;
	isMouseDragging = false;
	isMouseDown	= false;
	isRegionsEnabled = true;
	downRegion = -1;
}

bool CTouchInput::IsRegionPressed(int id)
{
	if (!isRegionsEnabled)
	{
		return false;
	}

	return isRegionPressed && (downRegion == id);
}

bool CTouchInput::IsRegionDown(int id)
{
	if (!isRegionsEnabled)
	{
		return false;
	}

	return (isMouseDown || isMouseDragging) && downRegion == id;
}

bool CTouchInput::IsRegionDown(const char* name)
{
	if (!isRegionsEnabled)
	{
		return false;
	}

	return strcmp(activeRegions[downRegion].name, name) == 0;
}

bool CTouchInput::IsRegionDownMult(const char* name)
{
	if (!isRegionsEnabled)
	{
		return false;
	}

	return (isMouseDown || isMouseDragging) && IsMouseInRegion(name);
}

int CTouchInput::GetSelectedRegion()
{
	//for(int i=0; i<regionNum; i++)
	for(int i=regionNum-1; i>=0; i--)
	{
		if(IsMouseInRegion(activeRegions[i].name))
		{
			return i;
		}
	}
	return -1;
}

int CTouchInput::GetPressedRegion()
{
	//for(int i=0; i<regionNum; i++)
	for(int i=regionNum-1; i>=0; i--)
	{
		if(IsRegionPressed(activeRegions[i].name))
		{
			return i;
		}
	}
	return -1;
}

